
//
// 101214 - AH - (Hector) Created.
// 101217a- AH - printRetrieved renamed to retrievedTreesToString.
// 101217b- AH - retrievedTreesToString(List<AttributeObject>, List<Tree>).
// 101218a- AH - (Garage) (*) centrifuge(List<AttributeObject>, List<AttributeObject>, List<AttributeObject>, List<AttributeObject>).
// 101218b- AH - centrifuge(List<AttributeObject>, List<AttributeObject>, List<AttributeObject>, List<AttributeObject>)
//               now returns number of types in output found.
// 101228 - AH - Minor java doc fix, bug discovered by java doc compiler.
// 120128 - AH - (Garage) two years later (okidoki less than but still) :-) 
//               centrifuge support new ontology ProductTable.
//

package org.soekrat.engine.rethor;

import java.io.CharArrayWriter;
import java.io.PrintWriter;
import java.util.HashSet;
import java.util.List;
import java.util.Set;

import org.soekrat.AttributeObject;
import org.soekrat.engine.forest.Forest;
import org.soekrat.engine.forest.Tree;
import org.soekrat.engine.mine.Mine;
import org.soekrat.engine.mine.Resource;
import org.soekrat.engine.network.Cluster;
import org.soekrat.engine.network.Network;
import org.soekrat.engine.ontology.ptable.Product;
import org.soekrat.engine.retrieval.forest.ForestRetrievalStrategy;
import org.soekrat.engine.wheel.Wheel;

/**
 * <p>
 *   Rethor utility methods.
 * </p>
 * @author Arne Halvorsen (AH)
 * @author Laetitia Le Chatton (LLC)
 */
public final class RethorUtil 
{
  private RethorUtil(){} // Utility pattern dictates private constructor.
  
  /**
   * <p>
   *   Basic rethor 
   *   {@code String} presentation of 
   *   {@link ForestRetrievalStrategy}.
   * </p>
   * @param paint Result.
   * @return {@code String} presentation.
   */
  public static String retrievedTreesToString(List<AttributeObject> paint)
  {
    return retrievedTreesToString(paint, null);
  }
  
  /**
   * <p>
   *   Basic rethor 
   *   {@code String} presentation of 
   *   {@link ForestRetrievalStrategy}.
   * </p>
   * @param paint Result.
   * @param printed If not {@code null} will add
   *                {@link Tree}s which names are printed. Will remove old 
   *                content.
   * @return {@code String} presentation.
   */
  public static String retrievedTreesToString(List<AttributeObject> paint, 
    List<Tree> printed)
  {
    if (paint==null)
    {
      throw new NullPointerException("paint");
    }
    
    if (printed!=null) printed.clear();
    
    CharArrayWriter caw=new CharArrayWriter();
    PrintWriter pw=new PrintWriter(caw);
    
    Set<Object> shelf=new HashSet<Object>();
    
    for (AttributeObject curr : paint)
    {
      String s=retrievedTreesToString(curr, shelf, printed);
      if (s.length()!=0)
      {
        pw.println("--- New Folder ---");
        pw.println(s);
      }
    }
    
    pw.flush();
    return caw.toString();
  }
  
  private static String retrievedTreesToString(AttributeObject keyCandidate, 
    Set<Object> shelf, List<Tree> printed)
  {
    CharArrayWriter caw=new CharArrayWriter();
    PrintWriter pw=new PrintWriter(caw);
    
    retrievedTreesToString(keyCandidate, pw, 0, shelf, printed);
    
    pw.flush();
    return caw.toString();
  }
  
  private static void retrievedTreesToString(AttributeObject keyCandidate, 
    PrintWriter pw, int level, Set<Object> shelf, List<Tree> printed)
  {
    Tree tree=(keyCandidate instanceof Tree) ? (Tree)keyCandidate : null;
     
    if (tree!=null && tree.getBoolean("key") && !shelf.contains(tree))
    {
      StringBuilder sb=new StringBuilder();
      for (int i=0; i<level; i++) sb.append("     ");
      
      sb.append(tree.getName());
       
      pw.println(sb);
      
      if (printed!=null) printed.add(tree);
       
      shelf.add(tree);
    }
     
    if (tree!=null)
    {
      for (Tree child : tree) 
      {
        retrievedTreesToString(child, pw, level+1, shelf, printed);  
      }
    }
  }
  
  ////
  
  public static Tree buildRetrievedTree(List<AttributeObject> paint)
  {
    Tree root=new Tree("root");
    
    Set<Object> shelf=new HashSet<Object>();
    
    for (AttributeObject curr : paint)
    {
      buildRetrievedTree(curr, root, shelf);
    }
    
    return root;
  }
  
  private static void buildRetrievedTree(AttributeObject kc, Tree parent, 
    Set<Object> shelf)
  {
    Tree tree=(kc instanceof Tree) ? (Tree)kc : null;
    
    Tree nparent=null;
    if (tree!=null && tree.getBoolean("key") && !shelf.contains(tree))
    {
      String name=tree.getName();
      nparent=parent.createChild(name);
       
      shelf.add(tree);
    }
     
    if (tree!=null && nparent!=null)
    {
      for (Tree child : tree) 
      {
        buildRetrievedTree(child, nparent, shelf);  
      }
    }
  }
  
  /**
   * <p>
   *   Separate 
   *   {@link Wheel} output into output from the possible sources. 
   * </p>
   * <p>
   *   Old content in {@code resources}, {@code trees} and {@code clusters} is 
   *   removed.
   * </p>
   * @param paint     {@code Wheel} output.
   * @param resources From the
   *                  {@link Mine} added here.
   * @param trees     From the
   *                  {@link Forest} added here.
   * @param clusters  From the
   *                  {@link Network} added here.
   * @return Number of types of output found, {@code 0, 1} or {@code 3}.                 
   */
  public static int centrifuge(List<AttributeObject> paint, 
    List<AttributeObject> resources, List<AttributeObject> trees, 
    List<AttributeObject> clusters, List<AttributeObject> products)
  {
    if (paint==null)
    {
      throw new NullPointerException("paint");
    }
    if (resources==null)
    {
      throw new NullPointerException("resource");
    }
    if (trees==null)
    {
      throw new NullPointerException("trees");
    }
    if (clusters==null)
    {
      throw new NullPointerException("clusters");
    }
    if (products==null)
    {
      throw new NullPointerException("products");
    }
    
    resources.clear();
    trees.clear();
    clusters.clear();
    products.clear();
    
    for (AttributeObject curr : paint)
    {
           if (curr instanceof Resource) resources.add(curr);  
      else if (curr instanceof Tree)     trees.add(curr);
      else if (curr instanceof Cluster)  clusters.add(curr);
      else if (curr instanceof Product)  products.add(curr);
    }
    
    int retVal=0;
    if (!resources.isEmpty()) retVal++;
    if (!trees.isEmpty())     retVal++;
    if (!clusters.isEmpty())  retVal++;
    if (!products.isEmpty())  retVal++;
    
    return retVal;
  }
  
}
